/// \file		WnConnection.h
/// \brief		WIND连接对象类的声明文件
/// \author		xuefeng
/// \version	1.0
/// \date		2011-07-19
/// \history	2011-07-19 新建

#pragma once

#include "WnConnBase.h"
#include "boost/thread.hpp"
#include <boost/asio/io_service.hpp>

// 读写锁
typedef boost::shared_lock<boost::shared_mutex> readLock;
typedef boost:: unique_lock<boost::shared_mutex> writeLock;

// 该类代表一个一个的session
template<typename Protocol>
class WnConnection : public WnConnBase, public boost::enable_shared_from_this<WnConnection<Protocol> >
{
public:
  typedef typename Protocol::endpoint endpoint_type;
  typedef typename Protocol::socket socket_type;
  typedef typename Protocol::resolver resolver_type;

  /// \brief 构造函数
  /// \param apEndPoint 本地终端
  /// \param blRawData 原始数据标志
  /// \param oIoService IO异步处理服务
  WnConnection(END_POINT_APTR apEndPoint, boost::asio::io_service& oIoService)
    : WnConnBase(apEndPoint)
    , m_oSocket(oIoService)
    , m_oRemoteEndpoint()
    , m_oResolver(oIoService)
    , m_HB_interval(HEARTBEAT_INTERVAL)
  {}

  /// \brief 析构函数
  virtual ~WnConnection(void) 
  {

  }

  /// \brief 设置对手方
  /// \param strHostName 对方主机名
  /// \param strPort 对方端口号
  /// \return 0 设置成功，其他值为错误代码
  int SetAddr(const std::string& strHostName, const std::string& strPort);

  /// \brief 客户端开始连接函数
  void BeginConnect();

  /// \brief 服务端接收到连接的响应函数
  void OnAccept();

  /// \brief 异步发送函数
  /// \param oPacket 数据包
  /// \param blHighPriority 是否有高优先级
  /// \return 发送结果值
  ENU_ASYNSEND_RESULT AsyncSend(const PACKET_APTR& oPacket, bool blHighPriority);

  /// \brief 获取SOCKET
  /// \return SOCKET
  socket_type& GetSocket() { return m_oSocket; }

  /// \brief 获取对手方地址
  /// \return 对手方地址
  endpoint_type& GetRemoteEndPoint() { return m_oRemoteEndpoint; }

  void SetHBInterval(int HB_interval) {m_HB_interval = HB_interval;}

protected:
  /// 设置远端地址
  void SetRemoteEndpoint(const endpoint_type& oEndPoint) { m_oRemoteEndpoint = oEndPoint; }

  /// \brief 异步读函数
  void BeginRead();

  /// \brief 异步写函数
  void BeginWrite();

  /// \brief 处理连接事件
  /// \param oError 错误
  void HandleConnect(const boost::system::error_code& oErrorCode);

  /// \brief 处理数据接受事件
  /// \param oError 错误
  /// \param unTransBytes 传输的字节数
  void HandleRead(const boost::system::error_code& oErrorCode, std::size_t unTransBytes);

  /// \brief 处理数据发送事件
  /// \param oError 错误
  void HandleWrite(PACKET_APTR& pak, const boost::system::error_code& oErrorCode);

  /// \brief 关闭连接处理函数
  void OnClose();

private:
  // SOCKET对象
  socket_type m_oSocket;

  // 连接对手方地址
  endpoint_type m_oRemoteEndpoint;

  // 分解器
  resolver_type m_oResolver;

  // 心跳间隔
  int m_HB_interval;
};

template<typename Protocol>
int WnConnection<Protocol>::SetAddr(const std::string& strHostName, const std::string& strPort)
{
  int nResult = 0;
  typename resolver_type::query oQuery(strHostName, strPort);

  boost::system::error_code oErrorCode = boost::asio::error::host_not_found;
  typename resolver_type::iterator itEndpoint = m_oResolver.resolve(oQuery, oErrorCode);

  if(oErrorCode)
  {
    nResult = oErrorCode.value();

    // 发送通知
    {
      stringstream ss;
      ss << "file:" << __FILE__ << ", function:" << __FUNCTION__ << ", line:" << __LINE__ << ". @@@. "
        << "地址错误. info:" << oErrorCode.message() << ". strHostName:" << strHostName << ", strPort" << strPort;
      OnMsg(2, ss.str());
    }
  }
  else
    SetRemoteEndpoint(*itEndpoint);
  return nResult;
}

template<typename Protocol>
inline void WnConnection<Protocol>::BeginConnect()
{
  m_oSocket.async_connect(m_oRemoteEndpoint, boost::bind(&WnConnection<Protocol>::HandleConnect, shared_from_this(), boost::asio::placeholders::error));
}

template<typename Protocol>
void WnConnection<Protocol>::HandleConnect(const boost::system::error_code& oErrorCode)
{
  if(!oErrorCode)
  {
    // 清空发送队列
    m_oSendPacketList.clear();

    // 设置已连接状态
    SetConnectedState(true);

    // 设置远端地址
    SetRemoteEndpoint(m_oSocket.remote_endpoint());

    // 开始读
    BeginRead();

    // 通知连接成功
    {
      readLock lock(m_mtx_apLocalEndPoint);
      if(m_apLocalEndPoint)
        m_apLocalEndPoint->OnConnect(shared_from_this(), E_CONNECT_SUCCESS);
    }
  }
  else
  {
    stringstream ss;
    ss << "file:" << __FILE__ << ", function:" << __FUNCTION__ << ", line:" << __LINE__ << ". @@@. "
      << "连接失败. info:" << oErrorCode.message();
    OnMsg(2, ss.str());

    // 通知连接失败
    {
      //readLock lock(m_mtx_apLocalEndPoint);
      if(m_apLocalEndPoint)
        m_apLocalEndPoint->OnConnect(shared_from_this(), E_CONNECT_IOERROR);
    }
  }
}

template<typename Protocol>
void WnConnection<Protocol>::OnAccept()
{
  // 清空发送队列
  m_oSendPacketList.clear();

  // 设置已连接状态
  SetConnectedState(true);

  // 设置远端地址
  SetRemoteEndpoint(m_oSocket.remote_endpoint());

  // 通知连接成功
  if(m_apLocalEndPoint)
    m_apLocalEndPoint->OnAccept(shared_from_this());

  // 开始读
  BeginRead();
}

template<typename Protocol>
ENU_ASYNSEND_RESULT WnConnection<Protocol>::AsyncSend(const PACKET_APTR& oPacket, bool blHighPriority)
{
  ENU_ASYNSEND_RESULT eResult = E_AR_SUCCESS;

  if(!IsConnected())
  {
    eResult = E_AR_NOCONNECT;
    return eResult;
  }

  boost::mutex::scoped_lock lock(m_oWritingMutex);
  if(blHighPriority)
    m_oSendPacketList.push_front(oPacket);
  else
    m_oSendPacketList.push_back(oPacket);

  if(m_blWriting)
    return eResult;

  m_blWriting = true;
  BeginWrite();
  return eResult;
}

template<typename Protocol>
void WnConnection<Protocol>::BeginRead()
{
  boost::asio::async_read(m_oSocket, buffer(m_pbRecvBuffer, m_nRecvBufferSize),
	  transfer_at_least(1), boost::bind(&WnConnection<Protocol>::HandleRead,
		  shared_from_this(), boost::asio::placeholders::error,
		  boost::asio::placeholders::bytes_transferred));
}

template<typename Protocol>
void WnConnection<Protocol>::BeginWrite()
{
  // 取队首包
  auto pak = m_oSendPacketList.front();
  m_oSendPacketList.pop_front();

  boost::asio::async_write(m_oSocket, 
	  buffer(pak->GetPacketData(), pak->GetPacketLength()),
	  boost::bind(&WnConnection<Protocol>::HandleWrite,
		  shared_from_this(), pak, boost::asio::placeholders::error));
}

template<typename Protocol>
void WnConnection<Protocol>::HandleRead(const boost::system::error_code& oErrorCode, std::size_t unTransBytes)
{
  if(!IsConnected())
    return;

  if(!oErrorCode)
  {
    HandleInData(shared_from_this(), unTransBytes);

    // 继续读
    BeginRead();
  }
  else
  {
    boost::shared_ptr<WnConnection<Protocol> > apConnection = shared_from_this();

    // 一般是客户端断开，因此不写日志
    //// 发送通知
    //{
    //  stringstream ss;
    //  ss << "file:" << __FILE__ << ", function:" << __FUNCTION__ << ", line:" << __LINE__ << ". @@@. "
    //    << "socket读错误. info:" << oErrorCode.message();
    //  OnMsg(2, ss.str());
    //}

    // 通知连接断开
    {
      //readLock lock(m_mtx_apLocalEndPoint);
      if(m_apLocalEndPoint)
        m_apLocalEndPoint->OnDisconnect(apConnection, E_DISCONNECT_IOERROR);
    }

    // 关闭SOCKET
    Close();
  }
}

template<typename Protocol>
void WnConnection<Protocol>::HandleWrite(
	PACKET_APTR& pak, const boost::system::error_code& oErrorCode)
{
  if(!IsConnected())
  {
    boost::mutex::scoped_lock lock(m_oWritingMutex);
    m_oSendPacketList.clear();
    return;
  }

  if(!oErrorCode)
  {
    boost::mutex::scoped_lock lock(m_oWritingMutex);

    if(m_oSendPacketList.empty())
    {
      m_blWriting = false;
      return;
    }
    BeginWrite();
  }
  else
  {
    boost::shared_ptr<WnConnection<Protocol> > apConnection = shared_from_this();

    // 发送通知
    {
      stringstream ss;
      ss << "file:" << __FILE__ << ", function:" << __FUNCTION__ << ", line:" << __LINE__ << ". @@@. "
        << "socket写错误. info:" << oErrorCode.message();
      OnMsg(2, ss.str());
    }

    // 通知连接断开
    {
      //readLock lock(m_mtx_apLocalEndPoint);
      if(m_apLocalEndPoint)
        m_apLocalEndPoint->OnDisconnect(apConnection, E_DISCONNECT_IOERROR);
    }

    // 关闭SOCKET
    Close();

    {
      boost::mutex::scoped_lock lock(m_oWritingMutex);
      m_oSendPacketList.clear();
    }
  }
}

template<typename Protocol>
inline void WnConnection<Protocol>::OnClose()
{
  try
  {
	  // 关闭连接前留0秒给客户接收数据
	  boost::asio::socket_base::linger op_lin(true, 0);
	  m_oSocket.set_option(op_lin);
	  m_oSocket.close();
  }
  catch (std::exception& e)
  {
    stringstream ss;
    ss << "file:" << __FILE__ << ", function:" << __FUNCTION__ << ", line:" << __LINE__ << ". @@@. "
      << "thread id: " << boost::this_thread::get_id() << " " << e.what();
    OnMsg(2, ss.str());
  }
  catch (...)
  {
    stringstream ss;
    ss << "file:" << __FILE__ << ", function:" << __FUNCTION__ << ", line:" << __LINE__ << ". @@@. "
      << "thread id: " << boost::this_thread::get_id() << " " << "unknown";
    OnMsg(2, ss.str());
  }
}
